package com.qdxwx.sms;


import com.qdxwx.common.utils.PropertyUtils;
import com.qdxwx.sms.tencent.common.Credential;
import com.qdxwx.sms.tencent.common.exception.TencentCloudSDKException;
import com.qdxwx.sms.tencent.common.profile.ClientProfile;
import com.qdxwx.sms.tencent.common.profile.HttpProfile;
import com.qdxwx.sms.tencent.common.profile.Region;
import com.qdxwx.sms.tencent.v20210111.SmsClient;
import com.qdxwx.sms.tencent.v20210111.models.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author ZhiYong
 * @dateTime 2020/5/13 11:03
 * @description
 */
public class QdxSmsClient {

    private SmsClient smsClient;
    private String sdkAppId;//短信应用Id
    private String sdkSign;//短信签名

    private static final QdxSmsClient INSTANCE = new QdxSmsClient();

    public static QdxSmsClient getInstance() {
        return INSTANCE;
    }

    public QdxSmsClient() {
        Properties cfg = PropertyUtils.getInstance("sms-config");
        Map<String, Object> config = new HashMap<>();
        config.put("secretId", cfg.getProperty("tencent.secretId"));
        config.put("secretKey", cfg.getProperty("tencent.secretKey"));
        initSmsClient(config);
    }

    public QdxSmsClient(Map<String, Object> config) {
        initSmsClient(config);
    }

    public boolean sendRegisterCode(String phoneNumber, String code) {
        return sendSingle(phoneNumber, new String[]{code}, TencentSmsTemplateIds.register.id);
    }

    public boolean sendLoginCode(String phoneNumber, String code) {
        return sendSingle(phoneNumber, new String[]{code}, TencentSmsTemplateIds.login.id);
    }

    public boolean sendRePasswordCode(String phoneNumber, String code) {
        return sendSingle(phoneNumber, new String[]{code}, TencentSmsTemplateIds.rePassword.id);
    }

    public boolean sendOtherCode(String phoneNumber, String code) {
        return sendSingle(phoneNumber, new String[]{code}, TencentSmsTemplateIds.other.id);
    }

    /**
     * 您申请的xxx审批"未通过/已通过"，详情请登录OA查看。
     *
     * @param phoneNumber
     * @param param
     * @return
     */
    public boolean sendWorkResult(String phoneNumber, String... param) {
        return sendSingle(phoneNumber, param, TencentSmsTemplateIds.workResult.id);
    }

    /**
     * xxx提交了一条xxx申请等待着您的审批,详情请登录OA查看
     *
     * @param phoneNumber
     * @param param
     * @return
     */
    public boolean sendWorkApprove(String phoneNumber, String... param) {
        return sendSingle(phoneNumber, param, TencentSmsTemplateIds.workApprove.id);
    }

    /**
     * 尊敬的{1}，您已成功购买《{2}》课，开课时间{3}（此短信仅供参考，不作业务凭证）
     *
     * @param phoneNumber
     * @param param
     * @return
     */
    public boolean sendCourseBuy(String phoneNumber, String... param) {
        return sendSingle(phoneNumber, param, TencentSmsTemplateIds.courseBuy.id);
    }

    /**
     * 您有一笔提现申请待审批，请及时登录后台审核！
     *
     * @param phoneNumber
     * @return
     */
    public boolean sendMoneyApprove(String phoneNumber) {
        return sendSingle(phoneNumber, null, TencentSmsTemplateIds.moneyApprove.id);
    }

    public SendStatus[] sendBatch(String[] phoneNumber, String[] templateParams, String templateId) {

        if (phoneNumber == null || templateParams == null) return null;

        TencentSmsParams tsp = new TencentSmsParams();
        if (this.sdkAppId != null)
            tsp.setSdkAppId(this.sdkAppId);
        if (this.sdkSign != null)
            tsp.setSdkSign(this.sdkSign);
        tsp.setPhoneNumbers(phoneNumber);
        tsp.setTemplateParams(templateParams);
        tsp.setTemplateId(templateId);
        SendSmsResponse res = sendSms(tsp);
        //SendStatus[] sendStatuses = res.getSendStatusSet();
        // 输出json格式的字符串回包
        if (res == null) return null;

        //System.out.println(SendSmsResponse.toJsonString(res));
        // 也可以取出单个值，你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
        //System.out.println(res.getRequestId());
        return res.getSendStatusSet();

    }

    public boolean sendSingle(String phoneNumber, String[] params, String templateId) {

        if (phoneNumber == null) return false;

        TencentSmsParams tsp = new TencentSmsParams();
        if (this.sdkAppId != null)
            tsp.setSdkAppId(this.sdkAppId);
        if (this.sdkSign != null)
            tsp.setSdkSign(this.sdkSign);
        tsp.setPhoneNumber(phoneNumber);
        if (params != null) {
            tsp.setTemplateParams(params);
        }
        tsp.setTemplateId(templateId);
        SendSmsResponse res = sendSms(tsp);
        //SendStatus[] sendStatuses = res.getSendStatusSet();
        // 输出json格式的字符串回包
        if (res == null) return false;

        //System.out.println(SendSmsResponse.toJsonString(res));
        // 也可以取出单个值，你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
        //System.out.println(res.getRequestId());
        SendStatus status = res.getSendStatusSet()[0];

        return status.getCode().equalsIgnoreCase("OK");
    }

    /**
     * @param params 短信参数
     * @return bool
     */
    public SendSmsResponse sendSms(TencentSmsParams params) {
        /* 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
         * 你可以直接查询SDK源码确定接口有哪些属性可以设置
         * 属性可能是基本类型，也可能引用了另一个数据结构
         * 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明 */
        SendSmsRequest req = new SendSmsRequest();
        /* 填充请求参数,这里request对象的成员变量即对应接口的入参
         * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
         * 基本类型的设置:
         * 帮助链接：
         * 短信控制台: https://console.cloud.tencent.com/sms/smslist
         * sms helper: https://cloud.tencent.com/document/product/382/3773 */
        req.setSmsSdkAppId(params.getSdkAppId());
        req.setSignName(params.getSdkSign());

        /* 国际/港澳台短信 senderid: 国内短信填空，默认未开通，如需开通请联系 [sms helper] */
        //String senderid = "xxx";
        //req.setSenderId(senderid);

        //用户的 session 内容: 可以携带用户侧 Id 等上下文信息，server 会原样返回
        if (params.getSessionContext() != null) {
            req.setSessionContext(params.getSessionContext());
        }

        /* 短信码号扩展号: 默认未开通，如需开通请联系 [sms helper] */
        //String extendcode = "xxx";
        //req.setExtendCode(extendcode);
        req.setPhoneNumberSet(params.getPhoneNumbers());
        /* 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 */
        req.setTemplateId(params.getTemplateId());
        if (params.getTemplateParams() != null) {
            req.setTemplateParamSet(params.getTemplateParams());
        }

        try {
            /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 SendSmsResponse 类的实例，与请求对象对应 */
            return smsClient.SendSms(req);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return null;
        }
    }


    public void statusByPhoneNumber(String phoneNumber) {

        /* 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
         * 你可以直接查询SDK源码确定接口有哪些属性可以设置
         * 属性可能是基本类型，也可能引用了另一个数据结构
         * 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明 */
        PullSmsSendStatusByPhoneNumberRequest req = new PullSmsSendStatusByPhoneNumberRequest();

        /* 填充请求参数,这里request对象的成员变量即对应接口的入参
         * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
         * 基本类型的设置:
         * 帮助链接：
         * 短信控制台: https://console.cloud.tencent.com/sms/smslist
         * sms helper: https://cloud.tencent.com/document/product/382/3773 */
        TencentSmsParams params = new TencentSmsParams();

        req.setSmsSdkAppId(params.getSdkAppId());
        req.setPhoneNumber(phoneNumber);
        /* 拉取起始时间，UNIX 时间戳（时间：秒） */

        Long sendDateTime = 1572859620L;
        req.setBeginTime(sendDateTime);

        /* 偏移量 注：目前固定设置为0 */
        Long offset = 0L;
        req.setOffset(offset);
        /* 拉取最大条数，最多100条 */
        Long limit = 100L;
        req.setLimit(limit);
        try {
            /* 通过 client 对象调用 PullSmsSendStatusByPhoneNumber 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 PullSmsSendStatusByPhoneNumberResponse 类的实例，与请求对象对应 */

            PullSmsSendStatusByPhoneNumberResponse res = smsClient.PullSmsSendStatusByPhoneNumber(req);
            // 输出json格式的字符串回包
            System.out.println(PullSmsSendStatusByPhoneNumberResponse.toJsonString(res));
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
    }

    private void initSmsClient(Map<String, Object> config) {
        Object secretId = config.get("secretId");
        Object secretKey = config.get("secretKey");
        //兼容
        if (secretId == null) {
            secretId = config.get("SecretId");
        }
        if (secretKey == null) {
            secretKey = config.get("SecretKey");
        }
        if (secretId == null || secretKey == null) {
            System.out.println("InitSmsClient:secretId or secretKey is null");
            return;
        }
        if (config.get("sdkAppId") != null) {
            this.sdkAppId = config.get("sdkAppId").toString();
        }
        if (config.get("sdkSign") != null) {
            this.sdkSign = config.get("sdkSign").toString();
        }
        /* 必要步骤：
         * 实例化一个认证对象，入参需要传入腾讯云账户密钥对secretId，secretKey。
         * 这里采用的是从环境变量读取的方式，需要在环境变量中先设置这两个值。
         * 你也可以直接在代码中写死密钥对，但是小心不要将代码复制、上传或者分享给他人，
         * 以免泄露密钥对危及你的财产安全。
         * CAM密匙查询: https://console.cloud.tencent.com/cam/capi*/
        Credential cred = new Credential(secretId.toString(), secretKey.toString());

        // 实例化一个http选项，可选，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        /* SDK默认使用POST方法。
         * 如果你一定要使用GET方法，可以在这里设置。GET方法无法处理一些较大的请求 */
        httpProfile.setReqMethod("POST");
        /* SDK有默认的超时时间，非必要请不要进行调整
         * 如有需要请在代码中查阅以获取最新的默认值 */
        httpProfile.setConnTimeout(60);
        /* SDK会自动指定域名。通常是不需要特地指定域名的，但是如果你访问的是金融区的服务
         * 则必须手动指定域名，例如sms的上海金融区域名： sms.ap-shanghai-fsi.tencentcloudapi.com */
        httpProfile.setEndpoint("sms.tencentcloudapi.com");

        /* 非必要步骤:
         * 实例化一个客户端配置对象，可以指定超时时间等配置 */
        ClientProfile clientProfile = new ClientProfile();
        /* SDK默认用TC3-HMAC-SHA256进行签名
         * 非必要请不要修改这个字段 */
        clientProfile.setSignMethod("HmacSHA256");
        clientProfile.setHttpProfile(httpProfile);
        /* 实例化要请求产品(以sms为例)的client对象
         * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，或者引用预设的常量 */

        smsClient = new SmsClient(cred, Region.Guangzhou.toString(), clientProfile);
    }

}